package com.dds.demo.config.aspect;

import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.sql.DataSource;

import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;
import org.springframework.boot.bind.RelaxedDataBinder;
import org.springframework.boot.bind.RelaxedPropertyResolver;
import org.springframework.context.ApplicationContext;
import org.springframework.core.annotation.Order;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.core.env.Environment;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.dds.demo.util.SpringContextUtil;

//@Aspect
//@Order(5) // 保证该执行顺序

//1s
//@Component
public class DynamicDataSourceAspect {
	@Autowired
	ApplicationContext ctx;
	@Autowired
	Environment env;
	// 默认数据源
	private DataSource defaultDataSource;
	private String dataSource = "";

	private ConversionService conversionService = new DefaultConversionService();

	private final Logger logger = LoggerFactory.getLogger(DynamicDataSourceAspect.class);
	// 数据源配置信息
	private PropertyValues dataSourcePropertyValues;

	@Pointcut("execution(public * com.dds.demo.controller..*.*(..))")
	public void webLog() {
	}

	@Before("webLog()")
	public void changeDataSource(JoinPoint point) throws Throwable {
		// 获取当前的指定的数据源;
		// 如果不在我们注入的所有的数据源范围之内，那么输出警告信息，系统自动使用默认的数据源。
		ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
		HttpServletRequest request = attributes.getRequest();
		getContextHolderInfo(request);
	//	ContextHolder.setDataSource("test1");
	}

	@AfterReturning(returning = "ret", pointcut = "webLog()")
	public void restoreDataSource(JoinPoint point) {
		// 方法执行完毕之后，销毁当前数据源信息，进行垃圾回收。
		// ContextHolder.clearDataSourceType();
	}

	/**
	 * 获取ContextHolder信息
	 * 
	 * @param request
	 */
	public void getContextHolderInfo(HttpServletRequest request) {
		Map<String, DataSource> targetDataSources = new HashMap<>();
		String userId = request.getParameter("userId");
		
		if (StringUtils.isEmpty(userId)) {
		} else {

			if (userId.equals("1")) {
				dataSource = "test1";
				targetDataSources.put(dataSource, buildDataSource(test1()));
			} else if (userId.equals("2")) {
				dataSource = "test2";
				//targetDataSources.put(dataSource, buildDataSource(test2()));
				defaultDataSource=buildDataSource(test3());
			} else if (userId.equals("3")) {
				dataSource = "test3";
				targetDataSources.put(dataSource, buildDataSource(test3()));
			}
		}
		DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory) SpringContextUtil.getApplicationContext().getAutowireCapableBeanFactory();
		Object obj = defaultListableBeanFactory.getBean("dataSource");
		System.out.println(obj);
		// 创建DynamicDataSource
		GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
		beanDefinition.setBeanClass(DynamicDataSourceAspect.class);

		beanDefinition.setSynthetic(true);
		MutablePropertyValues mpv = beanDefinition.getPropertyValues();
		mpv.addPropertyValue("defaultTargetDataSource", defaultDataSource);
		defaultListableBeanFactory.registerBeanDefinition("dataSource", beanDefinition);
		//ContextHolder.setDataSource(dataSource);
	}

	Map<String, Object> test1() {
		Map<String, Object> dsMap = new HashMap<>();
		dsMap.put("driverClassName", "com.mysql.jdbc.Driver");
		dsMap.put("url", "jdbc:mysql://localhost:3306/test1");
		dsMap.put("username", "root");
		dsMap.put("password", "root");
		return dsMap;
	}

	Map<String, Object> test2() {
		Map<String, Object> dsMap = new HashMap<>();
		dsMap.put("driverClassName", "com.mysql.jdbc.Driver");
		dsMap.put("url", "jdbc:mysql://localhost:3306/test2");
		dsMap.put("username", "root");
		dsMap.put("password", "root");
		return dsMap;
	}

	Map<String, Object> test3() {
		Map<String, Object> dsMap = new HashMap<>();
		dsMap.put("driverClassName", "com.mysql.jdbc.Driver");
		dsMap.put("url", "jdbc:mysql://localhost:3306/test3");
		dsMap.put("username", "root");
		dsMap.put("password", "root");
		return dsMap;
	}

	/**
	 * 为DataSource绑定更多数据
	 * 
	 * @param dataSource
	 * @param env
	 */
	private void dataBinder(DataSource dataSource, Environment env) {
		RelaxedDataBinder dataBinder = new RelaxedDataBinder(dataSource);
		dataBinder.setConversionService(conversionService);
		dataBinder.setIgnoreNestedProperties(false);// false
		dataBinder.setIgnoreInvalidFields(false);// false
		dataBinder.setIgnoreUnknownFields(true);// true

		if (dataSourcePropertyValues == null) {
			Map<String, Object> rpr = new RelaxedPropertyResolver(env, "spring.datasource.druid").getSubProperties(".");
			Map<String, Object> values = new HashMap<String, Object>(rpr);
			dataSourcePropertyValues = new MutablePropertyValues(values);
		}
		dataBinder.bind(dataSourcePropertyValues);

	}

	public DataSource buildDataSource(Map<String, Object> dsMap) {
		Object type = dsMap.get("type");
		if (type == null) {
			type = "com.alibaba.druid.pool.DruidDataSource";// 默认DataSource
		}
		Class<? extends DataSource> dataSourceType;

		try {
			dataSourceType = (Class<? extends DataSource>) Class.forName((String) type);
			String driverClassName = dsMap.get("driverClassName").toString();
			String url = dsMap.get("url").toString();
			String username = dsMap.get("username").toString();
			String password = dsMap.get("password").toString();
			DataSourceBuilder factory = DataSourceBuilder.create().driverClassName(driverClassName).url(url)
					.username(username).password(password).type(dataSourceType);
			return factory.build();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		return null;
	}

}
